; rddir.asm
; file directory management

	.include "rdglobal.inc"
	.include "rdmem.inc"
	_IN_RDDIR = 1
	.include "rddir.inc"

	.macro dir_first
			lda #<directory		; set ptr to first entry
			sta ptr
			lda #>directory
			sta ptr+1
	.endmacro
	
	.macro dir_next
			clc					; move ptr to next entry
			lda ptr
			adc #<.sizeof(DirEntry)
			sta ptr
			lda ptr+1
			adc #>.sizeof(DirEntry)
			sta ptr+1
	.endmacro

	.segment "BSS"
	
directory:		.REPEAT MAX_FILES
				.tag DirEntry
				.ENDREP  

name_buf:		.res MAX_NAME_LENGTH
	
	.segment "CODE"
	
; Initialises (clear) directory
dir_init:	dir_first
			ldx #MAX_FILES 		; init loop counter
			ldy #0
@init_loop:	jsr dir_del
			dex					
			beq @done
			dir_next			; move ptr to next entry
			jmp @init_loop
@done:		rts
	
; Finds an entry in the directory
; INPUT:	(ptr) ... pointer to name (terminated by zero)
; OUTPUT:	(ptr) ... pointer to dir entry
;			Carry ... Success (0) or not found (1)			
;			 
dir_find:	jsr get_name
			bcs @notfound		; name is empty
@end_cp:	dir_first
			ldx #MAX_FILES 		; init loop counter
@cmp_name:	ldy #0
			lda (ptr), y
			beq @next			; entry deleted
@cmp_loop:	lda name_buf, y
			bne @innam			; end of name?
			lda (ptr), y		; end of name?
			bne @next
			beq @found
@innam:		cmp #'*'			
			beq @found			; first wildcard match
			cmp #'?'
			bne @docmp
			lda (ptr), y
			beq @next
			bne @nxchar
@docmp:		cmp (ptr), y
			bne @next
@nxchar:	iny
			cpy #MAX_NAME_LENGTH
			beq @found			; end reached, full match
			bne @cmp_loop

@next:		dex					
			beq @notfound
			dir_next			; move ptr to next entry
			jmp @cmp_name
			
@notfound:	sec
			rts

@found:		clc
			rts			

; Adds an entry to the directory
; INPUT:	(ptr) ... pointer to name (terminated by zero)
; OUTPUT:	(ptr) ... pointer to dir entry
;			Carry ... Success (0) or failure (1)			
;			 
dir_add:	jsr get_name
			bcs @done
			dir_first
			ldx #MAX_FILES 		; init loop counter
@find_loop:	ldy #0
			lda (ptr), y
			beq @found
@next:		dex					
			beq @notfound		; last entry reached
			dir_next			; move ptr to next entry
			jmp @find_loop
@notfound:	sec					; failure
@done:		rts
@found:		ldy #0
@cp_loop:	lda name_buf, y
			sta (ptr), y
			beq @fin
			iny
			cpy #MAX_NAME_LENGTH
			beq @fin
			bne @cp_loop
@fin:		clc					; success
			rts

; Removes an entry from the directory
; INPUT:	(ptr) ... pointer to dir entry
; OUTPUT:	-			
;			 
dir_del:	lda #0
			tay
@clr_loop:	sta (ptr), y
			iny
			cpy #.sizeof(DirEntry)
			bcc @clr_loop
			rts
			
; Copies name to name_buf
; INPUT:	(ptr) ... pointer to name (terminated by zero)
;
get_name:	ldy #0				; copy name to name_buf
			lda (ptr), y
			beq @fail			; name is empty
@cp_loop:	lda (ptr), y
			sta name_buf, y
			cmp #$20
			bcs @noctrl
			lda #0
			sta name_buf, y
			beq @end_cp			
@noctrl:	iny
			cpy #16
			bne @cp_loop
@end_cp:	clc
			rts
@fail:		sec
			rts

;----------------------------------------------------------
; Directory as a file ("$") related routines
;----------------------------------------------------------

	.macro add_byte
			sta (ptr2), y
			inc ptr2
			.byte $D0, 2 ; bne +2
			inc ptr2+1
	.endmacro

	.segment "DATA"
	
icnt:		.res 1
npos:		.res 1
ftype:		.res 1 
	
	.segment "CODE"

; Writes the directory (file) to memory
; OUTPUT:
;	(ptr)	... start address
;	(ptr2)	... end address
; 
dir_build:	; init header
			ldx #0
@clrdir:	lda dirhdr, x
			sta dirbuf, x
			inx
			cpx #dirhdr_size
			bcc @clrdir			
			; set up ptr to buffer
			lda #<dirbdy
			sta ptr2
			lda #>dirbdy
			sta ptr2+1			
			; scan directory 
			ldx #MAX_FILES 		; init loop counter
			stx icnt
			dir_first
@dirloop:	ldy #0
			lda (ptr), y
			beq @next			; entry deleted
			
			jsr outent

@next:		dec icnt					
			beq @done
			dir_next			; move ptr to next entry
			jmp @dirloop
			
@done:		; write "bytes free"
			jsr bytfre			
			; write eof
			lda #0
			add_byte
			add_byte
			; return ptr to buf
			lda #<dirbuf
			sta ptr
			lda #>dirbuf
			sta ptr+1
			rts

; Adds dir entry to buffer
outent:		; write link
			lda #1					; write link
			add_byte	
			add_byte
			; write blocks
			ldy #DirEntry::blocks
			lda (ptr), y
			sta blklo
			iny
			lda (ptr), y
			sta blkhi
			ldy #0
			lda blklo				; write block count
			add_byte
			lda blkhi
			add_byte
			; add spaces
			lda blkhi
			cmp #$03
			beq @chklo
			bcs @endspc
@chklo:		ldx blklo
			cpx #$E8
			bcs @endspc
			lda #' '
			add_byte
			bit blkhi
			bne @endspc
			cpx #100
			bcs @endspc
			add_byte
			cpx #10
			bcs @endspc
			add_byte
@endspc:	; write file name
			lda #34
			add_byte
			ldx #MAX_NAME_LENGTH
			ldy #DirEntry::name
			sty npos
@nloop:		ldy npos
			lda (ptr), y
			beq @ndone
			ldy #0
			add_byte
			inc npos
			dex
			bne @nloop
@ndone:		lda #34
			ldy #0
			add_byte
			txa
			beq @sdone
			lda #' '
@sloop:		add_byte
			dex
			bne @sloop
@sdone:		; write file type
			ldy #DirEntry::type
			lda (ptr), y
			ldy #0
			sta ftype
			clc
			and #FILE_FLAG_OPEN
			bne @fcls
			lda #$2A
			bne @outflg 
@fcls:		lda #$20
@outflg:	add_byte
			lda ftype
			and #$07
			tax
			lda ftype1, x
			add_byte
			lda ftype2, x
			add_byte
			lda ftype3, x
			add_byte
			lda ftype
			and #FILE_FLAG_PROTECTED
			beq @eol
			lda #$3C
			add_byte
@eol:		lda #0				; write EOL
			add_byte
			rts

; Adds "bytes free" line to directory
bytfre:		lda #1				; write link
			add_byte	
			add_byte
			lda free_cnt		; write free blocks
			add_byte
			lda free_cnt+1
			add_byte
			ldx #0				; add text
@txtloop:	lda byf_text, x
			beq @eol
			add_byte
			inx
			bne @txtloop 
@eol:		lda #0				; write EOL
			add_byte
			rts

	.segment "RODATA"
	
byf_text:	.byte "blocks free.     ", 0

ftype1:		.byte 'd', 's', 'p', 'u', 'r', 'c', '?', '?'
ftype2:		.byte 'e', 'e', 'r', 's', 'e', 'b', '?', '?'
ftype3:		.byte 'l', 'q', 'g', 'r', 'l', 'm', '?', '?'

dirhdr:		.word $0401			; address
			.word $0101			; link
			.word 0				; blocks
			.byte $12			; RVS ON
			.byte 34,"fe3 - ram driver",34," ",VERSION
			.byte 0				; EOL 
	dirhdr_size = * - dirhdr

	.segment "BSS"

blklo:		.res 1
blkhi:		.res 1

dirbuf:		.res dirhdr_size
dirbdy:		.res 32*MAX_FILES + 2
